import { Application } from '../Application';
import { Connector } from '../connector/Connector';
import { ConnectorWs } from '../connector/ConnectorWs';
import { FrontendSession } from '../session/FrontendSession';
import { ISocket, miscCfg, RpcMsgId } from '../util/defines';
import { logger } from '../util/logger';
import { Server } from './Server';

/**
 * 前端服务器
 */
export class FrontendServer extends Server {

    constructor(app: Application, onStart?: () => void) {
        super(app, onStart);
        logger.info(`${this.app.svr.id}已启动,Rpc服务监听${this.app.svr.port}端口`, this, "constructor");
        this.connectMaster();
        let Connector = (miscCfg.connectorConstructor || ConnectorWs) as typeof ConnectorConstructor;
        new Connector(this.app).start(app.svr.clientPort, this.onConnectorStart.bind(this), this.onConnectorSocket.bind(this), this.onConnectorError.bind(this));
    }

    private onConnectorStart() {
        logger.info(`${this.app.svr.id}客户端连接服务已启动,监听${this.app.svr.clientPort}端口`, this, this.onConnectorStart);
    }

    private onConnectorSocket(socket: ISocket) {
        new ClientSocket(this.app, socket);
    }

    private onConnectorError(err: Error) {
        logger.error(err.message, this, this.onConnectorError);
        process.exit();
    }

    /**
     * 发送消息到客户端
     * @param uid 
     * @param msgId 
     * @param msg 
     */
    send(uid: number, msgId: number, msg?: any) {
        let sess = this.app.getClient(uid);
        sess && sess.send(msgId, msg);
    }

    /**
     * 发送多条消息到客户端
     * @param uid 
     * @param msgs 
     */
    sends(uid: number, msgs: { msgId: number; msg?: any; }[]) {
        let sess = this.app.getClient(uid);
        for (let msg of msgs) {
            sess.send(msg.msg, msg.msgId);
        }
    }

    /**
     * 广播消息到客户端
     * @param uids 
     * @param msgId 
     * @param msg 
     */
    boardcast(uids: number[], msgId: number, msg?: any) {
        let data = miscCfg.msgCoder.encode(msgId, msg);
        for (let uid of uids) {
            let sess = this.app.getClient(uid);
            sess && sess.socket.send(data);
        }
    }

    /**
     * 广播多条消息到客户端
     * @param uids 
     * @param msgs 
     */
    boardcasts(uids: number[], msgs: { msgId: number; msg?: any; }[]) {
        for (let msg of msgs) {
            this.boardcast(uids, msg.msgId, msg.msg);
        }
    }

    /**
     * 发送消息到所有客户端
     * @param msgId 
     * @param msg 
     */
    sendAll(msgId: number, msg?: any) {
        for (let uid in this.app.clients) {
            this.app.clients[uid].send(msgId, msg);
        }
    }

    /**
     * 发送消息到所有客户端
     * @param msgs 
     */
    sendAlls(msgs: { msgId: number; msg?: any; }[]) {
        for (let uid in this.app.clients) {
            for (let msg of msgs) {
                this.app.clients[uid].send(msg.msgId, msg.msg);
            }
        }
    }

}

/**
 * Connector构造,抽象实现,只是用来as过编译..
 */
class ConnectorConstructor extends Connector {
    start(port: number, onStart: () => void, onSocket: (socket: ISocket) => void, onError: (err: Error) => void): void { }
};

/**
 * 客户端连接Socket
 */
export class ClientSocket {

    app: Application;
    socket: ISocket;
    sess: FrontendSession;

    constructor(app: Application, socket: ISocket) {
        this.app = app;
        this.socket = socket;
        this.app.clientCount++;
        this.sess = new FrontendSession(this.app, this);
        this.socket.on("data", this.onData.bind(this));
        this.socket.on("close", this.onClose.bind(this));
        this.socket.on("error", this.onError.bind(this));
        miscCfg.onClient && miscCfg.onClient(this.sess);
    }

    /**
     * 发送数据给客户端
     */
    send(data: Buffer) {
        this.socket.send(data);
    }

    /**
     * 关闭连接
     */
    close() {
        this.socket.close();
    }

    private async onData(data: Buffer) {
        try {
            let msgId = miscCfg.msgCoder.decodeMsgId(data);
            if (miscCfg.msgFilter(this.sess, msgId.msgId)) return;

            let [stype, msgHandler, msgHandlerFunc] = this.app.msgCfg[msgId.msgId];
            if (stype === this.app.stype) {
                let msg = miscCfg.msgCoder.decodeMsgBuf(msgId.msgId, msgId.msgBuf);
                await this.app.frontendSvr.msgHandlers[msgHandler][msgHandlerFunc](this.sess, msg, msgId.msgId);
            } else {
                //后端消息 转发过去
                if (!this.sess.uid) return;

                let sid = this.app.getSvrWidthRouter(stype, this.sess).id;
                this.app.rpcService.send(sid, RpcMsgId.msgHandler, { sessBuf: this.sess.buf, data });
            }
        }
        catch (err) {
            logger.error("处理Msg时出现错误" + (err as Error).stack, this, this.onData);
            return;
        }
    }

    private onClose(err: Error) {
        miscCfg.onClientClose && miscCfg.onClientClose(this.sess, err);
        if (!this.app.hasClient(this.sess.uid)) return;
        this.app.clientCount--;
        delete this.app.clients[this.sess.uid];
    }

    private onError(err: Error) {
        this.onClose(err);
    }
}